package xyz.zdsoft.common.utils;


import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.Date;

/**
 * 时间工具类
 *
 * @author plastic
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    public static String YYYY = "yyyy";

    public static String YYYY_MM = "yyyy-MM";

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmssSSS";

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate() {
        return Date.from(LocalDateTime.now(ZoneId.of("Asia/Shanghai")).toInstant(ZoneOffset.of("+8")));
//        return Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static LocalDateTime getLocalDateTime() {
        return LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
//        return Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
    }

    public static Long getCurrentTimeStamp() {
        return LocalDateTime.now(ZoneId.of("Asia/Shanghai")).toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    public static int compare(String one, String two, String format) throws ParseException {
        return parseDate(one, format).compareTo(parseDate(two, format));
    }

    public static int compareToCurrent(String one, String format) throws ParseException {
        return compare(one, parseDateToStr(format, getNowDate()), format);
    }

    /**
     * 获取当前日期, 默认格式为yyyy-MM-dd
     *
     * @return String
     */
    public static String getCurrentDate() {
        return dateTimeNow(YYYY_MM_DD);
    }

    public static String getCurrentYear() {
        return dateTimeNow(YYYY);
    }

    public static String getCurrentQuarterStartDay() {
        String currentQuarterDate = null;
        int month = Integer.parseInt(DateUtils.getCurrentMonth().split("-")[1]);
        if (month >= 1 && month <= 3) {
            currentQuarterDate = DateUtils.getCurrentYear() + "-01-01";
        } else if (month >= 4 && month <= 6) {
            currentQuarterDate = DateUtils.getCurrentYear() + "-04-01";
        } else if (month >= 7 && month <= 9) {
            currentQuarterDate = DateUtils.getCurrentYear() + "-07-01";
        } else {
            currentQuarterDate = DateUtils.getCurrentYear() + "-10-01";
        }
        return currentQuarterDate;
    }

    public static String getCurrentMonth() {
        return dateTimeNow(YYYY_MM);
    }

    public static final String getCurrentTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static final String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

    public static final String dateTimeNow(final String format) {
        return parseDateToStr(format, getNowDate());
    }

    public static final String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static final String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    public static final Date dateTime(final String format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        return DateFormatUtils.format(getNowDate(), "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        return DateFormatUtils.format(getNowDate(), "yyyyMMdd");
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            return parseDate(str.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算两个时间差
     */
    public static String getDatePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 计算两个时间差
     */
    public static Long getDatePoorDay(Date small, Date big) {
        long day = 0l;
        SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD);
        try {
            small = sdf.parse(sdf.format(small));
            big = sdf.parse(sdf.format(big));
            Calendar cal = Calendar.getInstance();
            cal.setTime(small);
            long time1 = cal.getTimeInMillis();
            cal.setTime(big);
            long time2 = cal.getTimeInMillis();
            day = (time2 - time1) / (1000 * 3600 * 24);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return day;
    }

    public static Date getWorkDay(Date startDate, int workDay) {
        Calendar c1 = Calendar.getInstance();
        c1.setTime(startDate);
        for (int i = 0; i < workDay; i++) {
            c1.set(Calendar.DATE, c1.get(Calendar.DATE) + 1);
            int weekDay = dayForWeek(c1.getTime());
            if (Calendar.SATURDAY == weekDay || Calendar.SUNDAY == weekDay) {
                workDay = workDay + 1;
                c1.set(Calendar.DATE, c1.get(Calendar.DATE) + 1);
                continue;
            }
        }
        return c1.getTime();
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param smdate 较小的时间
     * @param bdate  较大的时间
     * @return 相差天数
     * @throws ParseException
     */
    public static int daysBetween(Date smdate, Date bdate) {
        long between_days = getDatePoorDay(smdate, bdate);
        return Integer.parseInt(String.valueOf(between_days));
    }


    /**
     * 　　 *字符串的日期格式的计算
     */
    public static int daysBetween(String smdate, String bdate) {
        long between_days = 0L;
        SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD);
        try {
            between_days = getDatePoorDay(sdf.parse(smdate), sdf.parse(bdate));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return Integer.parseInt(String.valueOf(between_days));
    }


    /**
     * 获取月初到现在的工作日天数
     */
    public static int getWorkDaysFormMonthStart() throws ParseException {
        String currentDate = getCurrentDate();
        Date monthStartDate = parseDate(currentDate.substring(0, 7) + "-01", YYYY_MM_DD);
        Date earlyWorkDay = parseDate(currentDate, YYYY_MM_DD);
        int betweenDayFromMonthStart = daysBetween(monthStartDate, earlyWorkDay);
        return getBetweenWorkDays(monthStartDate, betweenDayFromMonthStart, earlyWorkDay);
    }

    public static Date getBeforeEarlyWorkDay(Date targetDate) {
        Calendar c1 = Calendar.getInstance();
        c1.setTime(targetDate == null ? getNowDate() : targetDate);
        int workDay = 7;
        for (int i = workDay; i > 0; i--) {
            int weekDay = dayForWeek(c1.getTime());
            if (Calendar.SATURDAY == weekDay || Calendar.SUNDAY == weekDay) {
                workDay = workDay - 1;
                c1.set(Calendar.DATE, c1.get(Calendar.DATE) - 1);
                continue;
            } else {
                return c1.getTime();
            }
        }
        return c1.getTime();
    }

    public static int dayForWeek(Date time) {
        Calendar cal = Calendar.getInstance();
        int[] weekDays = {Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY};
        try {
            cal.setTime(time);
        } catch (Exception e) {
            e.printStackTrace();
        }
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1; // 指示一个星期中的某天。
        if (w < 0) {
            w = 0;
        }
        return weekDays[w];

    }


    public static Date getAfterEarlyWorkDay(Date targetDate) {
        Calendar c1 = Calendar.getInstance();
        c1.setTime(targetDate == null ? getNowDate() : targetDate);
        int workDay = 7;
        for (int i = 0; i < workDay; i++) {
            int weekDay = dayForWeek(c1.getTime());
            if (Calendar.SATURDAY == weekDay || Calendar.SUNDAY == weekDay) {
                workDay = workDay + 1;
                c1.set(Calendar.DATE, c1.get(Calendar.DATE) + 1);
                continue;
            } else {
                return c1.getTime();
            }
        }
        return c1.getTime();
    }


    private static int getBetweenWorkDays(Date startDate, int betweenWorkDays, Date targetDate) throws ParseException {
        targetDate = getBeforeEarlyWorkDay(targetDate);
        Date workDay = getWorkDay(startDate, betweenWorkDays);
        int compareResult = compare(parseDateToStr(YYYY_MM_DD, targetDate), parseDateToStr(YYYY_MM_DD, workDay), YYYY_MM_DD);
        // 就是今天
        if (compareResult == 0) {
            return betweenWorkDays + 1;
            // 当前时间在计算时间之后 天数加
        } else if (compareResult == 1) {
            return getBetweenWorkDays(startDate, (betweenWorkDays + 1), targetDate);
            // 当前时间在计算时间之前 天数减
        } else {
            return getBetweenWorkDays(startDate, (betweenWorkDays - 1), targetDate);
        }
    }

}
